#include "CConfig.h"

/* Set the value on the config file */
TInt CConfig::set_valueL(const TDesC& key,const TDesC8& newValue){
	
	TInt filesize;
	TInt pos1;
	TInt pos2;
	TInt len1;
	int len_current_value;
	int err;
	
	/* Load all the config file on the heap */
	this->openFileL(); //Open the file for reading
	iFile.Size(filesize);
	HBufC8 *buffer = HBufC8::NewL(filesize + 128); //We give space for the replacement
	CleanupStack::PushL(buffer);	
	TPtr8 ptr_buffer(buffer->Des());
	iFile.Read(ptr_buffer); //Read all data from the file and load into the buffer.
	
	HBufC8 *search;
	search = HBufC8::NewL(key.Length() + 2); // It holds <key>
	CleanupStack::PushL(search);
	TPtr8 pt(search->Des());
	_LIT(Kleft,"<"); //Is there other way of doing this?
	pt.Append(Kleft);
	pt.Append(key);
	_LIT(Kright,">");
	pt.Append(Kright);
	len1 = pt.Length();
	pos1 = buffer->Find(pt);
	//delete search;
	CleanupStack::PopAndDestroy(search);
	search=NULL;
	
	search = HBufC8::NewL(key.Length() + 3); //It holds </key>
	CleanupStack::PushL(search);
	_LIT(Kleftclose,"</");
	pt.Set(search->Des());
	pt.Append(Kleftclose);
	pt.Append(key);
	pt.Append(Kright);
	pos2 = buffer->Find(pt);
	//delete search;
	CleanupStack::PopAndDestroy(search);
	search=NULL;
	
	if (pos1 != KErrNotFound && pos2!= KErrNotFound)
	{
		len_current_value = pos2 - (pos1+len1);
		if ((newValue.Length()-len_current_value) >= 128) { /* Not enought space to add the new value */
			CleanupStack::PopAndDestroy(buffer);
			buffer=NULL;
			this->closeFile();
			return -2;
		}
		// Replace it
		ptr_buffer.Replace(pos1+len1,len_current_value,newValue);
		// Save the file
		iFile.SetSize(0);
		err = iFile.Write(ptr_buffer);
		if (err == KErrNone) 
			err = iFile.Flush();
		CleanupStack::PopAndDestroy(buffer);
		buffer=NULL;
		this->closeFile();
		return  err;	
	} 
	else {
		CleanupStack::PopAndDestroy(buffer);
		buffer=NULL;
		this->closeFile();
		return  -1;	
	}
		
}

/* Get the value of the specified key 
 * 
 * For instance : get_value(result,'interval')
 * If the key is not founded, error != 0
*/
TInt CConfig::get_valueL(const TDesC& key, TDes& value)
{
	TInt filesize;
	TInt pos1;
	TInt pos2;
	TInt len1;
	
	/* Load all the config file on the heap */
	this->openFileL(); //Open the file for reading
	iFile.Size(filesize);
	HBufC8 *buffer = HBufC8::NewL(filesize); //We assume the size file is small.
	CleanupStack::PushL(buffer);	
	TPtr8 ptr_buffer(buffer->Des());
	iFile.Read(ptr_buffer); //Read all data from the file and load into the buffer.
	this->closeFile(); //Close the file
	
	HBufC8 *search;
	search = HBufC8::NewL(key.Length() + 2); // It holds <key>
	CleanupStack::PushL(search);
	TPtr8 pt(search->Des());
	_LIT(Kleft,"<"); //Is there other way of doing this?
	pt.Append(Kleft);
	pt.Append(key);
	_LIT(Kright,">");
	pt.Append(Kright);
	len1 = pt.Length();
	pos1 = buffer->Find(pt);
	//delete search;
	CleanupStack::PopAndDestroy(search);
	search=NULL;
	
	search = HBufC8::NewL(key.Length() + 3); //It holds </key>
	CleanupStack::PushL(search);
	_LIT(Kleftclose,"</");
	pt.Set(search->Des());
	pt.Append(Kleftclose);
	pt.Append(key);
	pt.Append(Kright);
	pos2 = buffer->Find(pt);
	//delete search;
	CleanupStack::PopAndDestroy(search);
	search=NULL;

	if (pos1 != KErrNotFound && pos2!= KErrNotFound)
	{
		TPtrC8 sol = buffer->Mid(pos1 + len1,pos2 - (pos1 + len1));
		if (sol.Length() > value.MaxLength()) {
			CleanupStack::PopAndDestroy(buffer);
			buffer=NULL;
			return -1; //It is not enough space for copy value
		}
		value.Copy(sol);
		CleanupStack::PopAndDestroy(buffer);
		buffer=NULL;
		return KErrNone;
	}
	
	CleanupStack::PopAndDestroy(buffer);;
	buffer=NULL;
	return  -1;	
}

CConfig* CConfig::NewL(const TDesC& config_file)
{
	
	CConfig* self = new (ELeave) CConfig ();
	CleanupStack::PushL(self);
	self->ConstructL(config_file);
	CleanupStack::Pop();	
	return self;
}

CConfig::CConfig()
{
		
}

void CConfig::ConstructL(const TDesC& aConfigFile)
{	
	#ifdef __LOGGER
		iLog.Connect();
		iLog.CreateLog(_L("findme"),_L("CConfig.txt"),EFileLoggingModeOverwrite);
	#endif
	if (aConfigFile.Length() <= this->iConfigFile.MaxLength())
	{
		iConfigFile.Copy(aConfigFile);
		#ifdef __LOGGER
			iLog.WriteFormat(_L("Config file=%d"),iConfigFile.Length());
		#endif		
	}
	else 
	{
		User::Leave(KErrNotSupported);
	}
	User::LeaveIfError(iFs.Connect());
}

CConfig::~CConfig()
{
	iFs.Close();
	#ifdef __LOGGER
		iLog.CloseLog();
		iLog.Close();
	#endif
}

void CConfig::setConfigFile(const TDesC& aConfigFile) {
	if (aConfigFile.Length() <= this->iConfigFile.MaxLength())
	{
		iConfigFile.Zero();
		this->iConfigFile.Copy(aConfigFile);
		#ifdef __LOGGER
			iLog.WriteFormat(_L("Config file=%d"),iConfigFile.Length());
		#endif		
	}
	else 
	{
		User::Leave(KErrNotSupported);
	}	
}

void CConfig::get_nodeIdL(TUint& aNodeid) 
{
	TBuf<NODEIDLENGTH> node;
	_LIT(Knodeidtag, "nodeid");
	User::LeaveIfError(get_valueL(Knodeidtag, node));
	TLex string(node); //Convert string to TInt
	string.Val(aNodeid);
}

void CConfig::get_nodeIdL(TDes& aNodeid) 
{
	TInt error;
	_LIT(Knodeidtag, "nodeid");
	error = get_valueL(Knodeidtag, aNodeid);
	#ifdef __LOGGER
		if (error != KErrNone) 
			iLog.WriteFormat(_L("Error reading nodeid : %d"), error);
	#endif
	User::LeaveIfError(error);
}

void CConfig::set_nodeIdL(const TUint& aNodeid)
{
	TInt err;
	TBuf8<NODEIDLENGTH> node8;
	node8.Num(aNodeid);
	_LIT(Knodeidtag, "nodeid");
	err = set_valueL(Knodeidtag, node8);
	#ifdef __LOGGER
		if (err != KErrNone) 
			iLog.WriteFormat(_L("Error writing nodeid : %d"),err);
	#endif
	User::LeaveIfError(err);
}


//Get IAP GPRS configuration
void CConfig::get_GprsIAPL(TUint& aGprsIAP)
{
	TBuf<8> gprs;
	_LIT(Kgrps_id,"gprs_id");
	User::LeaveIfError(get_valueL(Kgrps_id, gprs));
	TLex string(gprs); //Convert string to TInt
	string.Val(aGprsIAP);
}

void CConfig::set_GprsIAPL(const TUint& aGprsIAP)
{
	TBuf8<16> ap8;
	TInt err;
	ap8.Num(aGprsIAP);
	_LIT(Kgrps_id,"gprs_id");
	err = set_valueL(Kgrps_id, ap8);
	#ifdef __LOGGER
		if (err != KErrNone) 
			iLog.WriteFormat(_L("Error writing gprs iap : %d"),err);
	#endif
	User::LeaveIfError(err);
}

void  CConfig::get_GprsNameL(TDes& aGprsName)
{
	_LIT(Kgprs_name,"gprs_name");
	User::LeaveIfError(get_valueL(Kgprs_name, aGprsName));	
}

void  CConfig::set_GprsNameL(const TDes& aGprsName)
{
	TInt err;
	if (aGprsName.Length() > GPRSNAMELENGTH) {
		User::Leave(KErrArgument);
	}
	TBuf8<SERVERNAMELENGTH> aname8;
	aname8.Copy(aGprsName);
	_LIT(Kgprs_name,"gprs_name");
	err = set_valueL(Kgprs_name, aname8);
	#ifdef __LOGGER
		if (err != KErrNone) 
			iLog.WriteFormat(_L("Error writing gprs name : %d"),err);
	#endif
	User::LeaveIfError(err);
}


void CConfig::get_serverL(TDes& aServer)
{
	_LIT(Kservertag,"server");
	User::LeaveIfError(get_valueL(Kservertag, aServer));	
}

void CConfig::set_serverL(const TDes& aServer)
{
	TInt err;
	if (aServer.Length() > SERVERNAMELENGTH) {
		User::Leave(KErrArgument);
	}
	TBuf8<SERVERNAMELENGTH> server8;
	server8.Copy(aServer);
	_LIT(Kservertag,"server");
	err = set_valueL(Kservertag, server8);
	#ifdef __LOGGER
		if (err != KErrNone) 
			iLog.WriteFormat(_L("Error writing server name : %d"),err);
	#endif
	User::LeaveIfError(err);
}

void CConfig::get_data_portL(TUint& aDataPort)
{
	TBuf<PORTLENGTH> port;
	_LIT(Kdata_porttag, "data_port");
	User::LeaveIfError(get_valueL(Kdata_porttag, port));
	TLex string(port); //Convert string to TInt
	string.Val(aDataPort);
}

void CConfig::get_data_portL(TDes& aDataPort) 
{
	TInt error;
	_LIT(Kdata_porttag, "data_port");
	error = get_valueL(Kdata_porttag, aDataPort);
	#ifdef __LOGGER
		if (error != KErrNone) 
			iLog.WriteFormat(_L("Error reading data port : %d"), error);
	#endif
	User::LeaveIfError(error);
}

void CConfig::set_data_portL(const TDesC& aDataPort) 
{
	TInt err;
	if (aDataPort.Length() > PORTLENGTH) {
		User::Leave(KErrArgument);
	}
	TBuf8<PORTLENGTH> dataport8;
	dataport8.Copy(aDataPort);
	_LIT(Kdata_porttag,"data_port");
	err = set_valueL(Kdata_porttag, dataport8);
	#ifdef __LOGGER
		if (err != KErrNone) 
			iLog.WriteFormat(_L("Error writing data port : %d"),err);
	#endif
	User::LeaveIfError(err);
}

void CConfig::set_data_portL(const TUint& aDataPort) 
{
	if (aDataPort < 0 || aDataPort > 65535) {
		User::Leave(KErrArgument);
	}
	TBuf<PORTLENGTH> dataport;
	dataport.Num(aDataPort);
	this->set_data_portL(dataport);
}

void CConfig::get_control_portL(TUint& control_port)
{
	TBuf<6> port;
	_LIT(Kcontrol_porttag, "control_port");
	User::LeaveIfError(get_valueL(Kcontrol_porttag, port));
	TLex string(port); //Convert string to TInt
	string.Val(control_port);
}
	
//Connection section

// Seconds between each data sended.
void CConfig::get_intervalL(TUint& aInterval)
{
	TBuf<INTERVALLENGTH> inte;
	_LIT(Kintervaltag,"interval");
	User::LeaveIfError(get_valueL(Kintervaltag, inte));
	TLex string(inte); //Convert string to TInt
	string.Val(aInterval);
}	

void CConfig::get_intervalL(TDes& aInterval) 
{
	TInt error;
	_LIT(Kintervaltag,"interval");
	error = get_valueL(Kintervaltag, aInterval);
	#ifdef __LOGGER
		if (error != KErrNone) 
			iLog.WriteFormat(_L("Error reading interval : %d"), error);
	#endif
	User::LeaveIfError(error);
}

void CConfig::set_intervalL(const TUint& aInterval)
{
	TBuf8<16> inter8;
	TInt err;
	inter8.Num(aInterval);
	_LIT(Kintervaltag,"interval");
	err = set_valueL(Kintervaltag, inter8);
	#ifdef __LOGGER
		if (err != KErrNone) 
			iLog.WriteFormat(_L("Error writing interval : %d"),err);
	#endif
	User::LeaveIfError(err);
}

void  CConfig::get_control_reconnection_interval(TUint& interval)
{
	TBuf<6> buf_interval;
	_LIT(Kcontrol_reconnectiontag,"reconnection_interval");
	User::LeaveIfError(get_valueL(Kcontrol_reconnectiontag, buf_interval));
	TLex string(buf_interval); //Convert string to TInt
	string.Val(interval);
}

void CConfig::get_phone_numberL(TDes& aPhoneNumber)
{
	TInt error;
	_LIT(Kphone_numberstag,"phone_number");
	error = get_valueL(Kphone_numberstag, aPhoneNumber);
	#ifdef __LOGGER
		if (error != KErrNone) 
			iLog.WriteFormat(_L("Error reading phone number : %d"),error);
	#endif
	User::LeaveIfError(error);
}

void CConfig::set_phone_numberL(const TDesC& aPhoneNumber) {
	TInt error;
	if (aPhoneNumber.Length() > PHONENUMBERLENGTH || aPhoneNumber.Length() < PHONELENTOCOMPARE) {
		User::Leave(KErrArgument);
	}
	TBuf8<PHONENUMBERLENGTH> phone8;
	phone8.Copy(aPhoneNumber);
	_LIT(Kphone_numberstag,"phone_number");
	error = set_valueL(Kphone_numberstag, phone8);
	#ifdef __LOGGER
		if (error != KErrNone) 
			iLog.WriteFormat(_L("Error writing phone number : %d"), error);
	#endif
	User::LeaveIfError(error);
}

void CConfig::get_gps_nameL(TDes& aGpsName) 
{
	TInt error;
	_LIT(Kgps_nametag,"gps_bt_name");
	error = get_valueL(Kgps_nametag, aGpsName);
	#ifdef __LOGGER
		if (error != KErrNone) 
			iLog.WriteFormat(_L("Error reading gps name : %d"),error);
	#endif
	User::LeaveIfError(error);
}

void CConfig::set_gps_nameL(const TDesC& aGpsName)
{
	TInt error;
	if (aGpsName.Length() > GPSNAMELENGTH) {
		User::Leave(KErrArgument);
	}
	TBuf8<GPSNAMELENGTH> name8;
	name8.Copy(aGpsName);
	_LIT(Kgps_nametag,"gps_bt_name");
	error = set_valueL(Kgps_nametag, name8);
	#ifdef __LOGGER
		if (error != KErrNone) 
			iLog.WriteFormat(_L("Error writing gps name : %d"), error);
	#endif
	User::LeaveIfError(error);
}

void CConfig::get_gps_addressL(TDes& aGpsAddress)
{
	TInt error;
	_LIT(Kgps_addresstag,"gps_bt_address");
	error = get_valueL(Kgps_addresstag, aGpsAddress);
	#ifdef __LOGGER
		if (error != KErrNone) 
			iLog.WriteFormat(_L("Error reading gps address : %d"),error);
	#endif
	User::LeaveIfError(error);
}

void CConfig::get_gps_addressL(TBTDevAddr& aGpsAddress)
{
	TBuf<GPSADDRESSLENGTH> address;
	get_gps_addressL(address);
	if (address.Length() != GPSADDRESSLENGTH) 
		User::Leave(KErrArgument);
	aGpsAddress.SetReadable(address);
}

void CConfig::set_gps_addressL(const TDes& aGpsAddress)
{
	TInt error;
	if (aGpsAddress.Length() > GPSADDRESSLENGTH) {
		User::Leave(KErrArgument);
	}
	TBuf8<GPSADDRESSLENGTH> address8;
	address8.Copy(aGpsAddress);
	_LIT(Kgps_addresstag,"gps_bt_address");;
	error = set_valueL(Kgps_addresstag, address8);
	#ifdef __LOGGER
		if (error != KErrNone) 
			iLog.WriteFormat(_L("Error writing gps name : %d"), error);
	#endif
	User::LeaveIfError(error);
}

void CConfig::set_gps_addressL(const TBTDevAddr& aGpsAddress)
{
	TInt error;
	TBuf<GPSADDRESSLENGTH> address;
	TBuf8<GPSADDRESSLENGTH> address8;
	aGpsAddress.GetReadable(address);
	address8.Copy(address);
	_LIT(Kgps_addresstag,"gps_bt_address");;
	error = set_valueL(Kgps_addresstag, address8);
	#ifdef __LOGGER
		iLog.Write(_L("Writing address : "));
		iLog.Write(address8);
		if (error != KErrNone) 
			iLog.WriteFormat(_L("Error writing gps name : %d"), error);
	#endif
	User::LeaveIfError(error);
}

// Open the file
void CConfig::openFileL()
{
	TInt error;
	error = iFile.Open(iFs,iConfigFile,EFileWrite);
#ifdef __LOGGER
	if (error != KErrNone) {
		iLog.WriteFormat(_L("File not found"));
		iLog.WriteFormat(iConfigFile);
	}
#endif
	User::LeaveIfError(error);	
}

void CConfig::closeFile()
{
	iFile.Close();
}

void CConfig::createConfigFile() 
{
	/* create the folder in case doesn't exits */
	iFs.MkDirAll(KConfigFolfer);
	/* deletes and created the file with default values */
	iFs.Delete(iConfigFile);
	iFile.Create(iFs,iConfigFile,EFileWrite);
	iFile.Write(_L8("#Config file of FindMe :\n"));
	iFile.Write(_L8("<nodeid>0</nodeid>\n"));
	iFile.Write(_L8("<phone_number>0</phone_number>\n"));
	iFile.Write(_L8("<gprs_name>NO SET</gprs_name>\n"));
	iFile.Write(_L8("<gprs_id>0</gprs_id>\n"));
	iFile.Write(_L8("<server>input.openfindme.com</server>\n"));
	iFile.Write(_L8("<control_port>3234</control_port>\n"));
	iFile.Write(_L8("<data_port>2233</data_port>\n")); 
	iFile.Write(_L8("<interval>10</interval>\n"));
	iFile.Write(_L8("<reconnection_interval>60</reconnection_interval>\n"));
	iFile.Write(_L8("<gps_bt_name>NO SET</gps_bt_name>\n"));
	iFile.Write(_L8("<gps_bt_address>000000000000</gps_bt_address>\n"));
	iFile.Flush();
	iFile.Close();
}

TBool CConfig::isValid()
{
	TUint unint;
	TBuf<256> sometext;
	TBTDevAddr btaddress;
	TRAPD(err,  get_nodeIdL(unint);
				get_GprsIAPL(unint);
				get_GprsNameL(sometext);
				get_serverL(sometext);
				get_data_portL(unint);
				get_control_portL(unint);
				get_intervalL(unint);
				get_control_reconnection_interval(unint);
				get_phone_numberL(sometext);
				get_gps_nameL(sometext);
				get_gps_addressL(btaddress);
				);
	if (err != KErrNone)
		return EFalse;
	return ETrue;
}